#include "scanner.h"
#include "parser.c"

#include <cstring>
#include <vector>
#include <string>
#include <iostream>
#include <fstream>

#define MODE_ERROR 0
#define MODE_CLASS 1
#define MODE_HTML 2

extern std::ifstream inputFile;
std::ifstream headerFile;

void tabs(int x) {
	while (x) {
		std::cout << "    ";
		--x;
	}
}

// Outputs the given string and replaces newline character escape sequences with <br /> tags.
// also, outputs tabnum tabs on each new line
void nl2br(const std::string& str, int tabnum) {
	std::string::const_iterator sit = str.begin();
	while (sit != str.end()) {
		if (*sit == '\\') {
			++sit;
			if (*sit == 'n') {
				std::cout << "<br />" << std::endl; tabs(tabnum);
				++sit;
				continue;
			}
		}
		std::cout << *sit;
		++sit;
	}	
}

int main(int argc, char* argv[]) {
	if (argc == 1) {
		std::cout << "JJsched help compiler" << std::endl;
		std::cout << "Compiles the command help from the given input file and outputs it in the desired format to the standard output" << std::endl << std::endl;
		std::cout << "synopsis:" << std::endl;
		std::cout << argv[0] << " --class FILE: Compiles the jjsched helper class that outputs command help" << std::endl;
		std::cout << argv[0] << " --html FILE: Compiles the html command documentation" << std::endl;
		return 0;
	}

	if (argc != 3) {
		std::cerr << "Incorrect number of arguments. Try running " << argv[0] << " without any arguments to get help on usage." << std::endl;
		return -1;
	}

	int mode = MODE_ERROR;

	if (!strcmp(argv[1], "--class")) mode = MODE_CLASS;
	else if (!strcmp(argv[1], "--html")) mode = MODE_HTML;

	if (mode == MODE_ERROR) {
		std::cerr << "Incorrect argument " << argv[1] << std::endl;
		return -1;
	}

	inputFile.open(argv[2]);

	if (!inputFile.is_open()) {
		std::cerr << "Could not open file \"" << argv[2] << "\" for reading." << std::endl;
		return -1;
	}

	inputFile >> std::noskipws; //This is needed for whitespaces to be visible to lex

	if (yyparse()) {
		std::cerr << "Bailing out due to parse error" << std::endl;
		return -1;
	}

	if (mode == MODE_CLASS) {
		//Output class header
		headerFile.open("header.txt");

		if (!headerFile.is_open()) {
			std::cerr << "Could not open file \"header.txt\" for reading." << std::endl;
			return -1;
		}

		while (!headerFile.eof()) {
			char c = (char) headerFile.get();
			if (c != -1)
				std::cout << c;
		}

		//Output help topics
		if (!topics.empty()) {
			tabs(2); std::cout << "if (topic.equals(\"topics\")) {" << std::endl;
			tabs(3); std::cout << "return \"List of available help topics. To get help for a given topic, type 'help topic'\\n\"" << std::endl;
			std::vector<topic>::iterator tit = topics.begin();
			while (tit != topics.end()) {
				tabs(4); std::cout << "+ \"" << tit->name;
				++tit;
 				if (tit != topics.end())
					std::cout << "\\n\"" << std::endl;
				else
					std::cout << "\";" << std::endl;
			}
			tabs(2); std::cout << "}" << std::endl;
		}

		//Output list of all commands
		if (!commands.empty()) {
			tabs(2); std::cout << "if (topic.equals(\"commands\")) {" << std::endl;
			tabs(3); std::cout << "return \"List of available commands. Type 'help command' to get help on a given command\\n\"" << std::endl;
			std::vector<command>::iterator cit = commands.begin();
			while (cit != commands.end()) {
				tabs(4); std::cout << "+ \"" << cit->name;
				++cit;
 				if (cit != commands.end())
					std::cout << "\\n\"" << std::endl;
				else
					std::cout << "\";" << std::endl;
			}
			tabs(2); std::cout << "}" << std::endl;
		}

		//Output help for each topic
		std::vector<topic>::iterator tit = topics.begin();
		while (tit != topics.end()) {
			if (!tit->name.empty() && !tit->description.empty()) {
				tabs(2); std::cout << "if (topic.equals(\"" << tit->name << "\")) {" << std::endl;
				tabs(3); std::cout << "return \"" << tit->description << "\\n\"" << std::endl;
				if (!tit->notes.empty()) {
					tabs(4); std::cout << "+ \"Notes:\\n" << tit->notes << "\\n\"" << std::endl;
				}
				if (!tit->also.empty()) {
					tabs(4); std::cout << "+ \"See also:\\n\"" << std::endl;
					tabs(4); std::cout << "+ \"";
					std::vector<std::string>::iterator ait = tit->also.begin();
					while (ait != tit->also.end()) {
						if (ait != tit->also.begin())
							std::cout << ", ";
						std::cout << *ait;
						++ait;
					}
					std::cout << "\";" << std::endl;
				}
				tabs(2); std::cout << "}" << std::endl;
			}
			++tit;
		}

		//Output help for each command
		std::vector<command>::iterator cit = commands.begin();
		while (cit != commands.end()) {
			if (!cit->name.empty() && !cit->description.empty()) {
				tabs(2); std::cout << "if (topic.equals(\"" << cit->name << "\")) {" << std::endl;
				tabs(3); std::cout << "return \"" << cit->description << "\\n\"" << std::endl;
				if (!cit->synopses.empty()) {
					std::vector<std::string>::iterator sit = cit->synopses.begin();
					int i = 0;
					while (sit != cit->synopses.end()) {
						tabs(4); std::cout << "+ \"" << i+1 << ">> " << *sit << "\\n\"" << std::endl;
						++sit; ++i;
					}
					i = 0;
					sit = cit->descriptions.begin();
					while (sit != cit->descriptions.end()) {
						tabs(4); std::cout << "+ \"Variant (" << i+1 << "): " << *sit << "\\n\"" << std::endl;
						++sit; ++i;
					}
				}
				if (!cit->notes.empty()) {
					tabs(4); std::cout << "+ \"Notes:\\n" << cit->notes << "\\n\"" << std::endl;
				}
				if (!cit->also.empty()) {
					tabs(4); std::cout << "+ \"See also:\\n\"" << std::endl;
					tabs(4); std::cout << "+ \"";
					std::vector<std::string>::iterator ait = cit->also.begin();
					while (ait != cit->also.end()) {
						if (ait != cit->also.begin())
							std::cout << ", ";
						std::cout << *ait;
						++ait;
					}
					std::cout << "\"" << std::endl;
				}
				tabs(2); std::cout << ";" << std::endl;
				tabs(2); std::cout << "}" << std::endl;
			}
			++cit;
		}

		//Close the class
		tabs(2); std::cout << "return \"No help on that command or command does not exist\";" << std::endl;
		tabs(1); std::cout << "}" << std::endl;
		std::cout << "}" << std::endl;
	} else if (mode == MODE_HTML) {
		//Output html header
		headerFile.open("htmlheader.txt");

		if (!headerFile.is_open()) {
			std::cerr << "Could not open file \"htmlheader.txt\" for reading." << std::endl;
			return -1;
		}

		while (!headerFile.eof()) {
			char c = (char) headerFile.get();
			if (c != -1)
				std::cout << c;
		}

		//Output list of all commands
		if (!commands.empty()) {
			tabs(2); std::cout << "<h2 id=\"commandlist\">Command list:</h2>" << std::endl;
			tabs(2); std::cout << "<ul>" << std::endl;
			std::vector<command>::iterator cit = commands.begin();
			while (cit != commands.end()) {
				tabs(3); std::cout << "<li><a href=\"#" << cit->name << "\">" << cit->name << "</a></li>" << std::endl;
				++cit;
			}
			tabs(2); std::cout << "</ul>" << std::endl;
		}

		//Output list of other help topics
		if (!commands.empty()) {
			tabs(2); std::cout << "<h2 id=\"topiclist\">Other help topics:</h2>" << std::endl;
			tabs(2); std::cout << "<ul>" << std::endl;
			std::vector<topic>::iterator tit = topics.begin();
			while (tit != topics.end()) {
				if (!tit->name.empty() && !tit->description.empty()) {
					tabs(3); std::cout << "<li><a href=\"#" << tit->name << "\">" << tit->name << "</a></li>" << std::endl;
				}
				++tit;
			}
			tabs(2); std::cout << "</ul>" << std::endl;
		}

		//Output help for each command
		std::vector<command>::iterator cit = commands.begin();
		while (cit != commands.end()) {
			if (!cit->name.empty() && !cit->description.empty()) {
				tabs(2); std::cout << "<hr />" << std::endl;
				tabs(2); std::cout << "<p id=\"" << cit->name << "\">" << std::endl;
				tabs(3); std::cout << "<a href=\"#commandlist\">Up</a>";
				tabs(3); std::cout << "<h3>" << cit->name << "</h3>" << std::endl;
				tabs(3); std::cout << "<p>"; nl2br(cit->description, 3); std::cout << "</p>" << std::endl;
				tabs(3); std::cout << "<h4>Synopsis:</h4>" << std::endl;
				if (cit->synopses.size() == 1) {
					tabs(3); std::cout << "<i>"; nl2br(cit->synopses[0], 3); std::cout << "</i>" << std::endl;
					tabs(3); std::cout << "<h4>Description:</h4>" << std::endl;
					if (cit->descriptions.size() > 0) {
						tabs(3); std::cout << "<p>";
						nl2br(cit->descriptions[0], 3);
						std::cout << "</p>" << std::endl;
					}
				} else {
					tabs(3); std::cout << "<ol>" << std::endl;
					for (int i = 0; i < cit->synopses.size(); ++i) {
						tabs(4); std::cout << "<li><i>"; nl2br(cit->synopses[i], 4); std::cout << "</i></li>" << std::endl;
					}
					tabs(3); std::cout << "</ol>" << std::endl;
					tabs(3); std::cout << "<h4>Description:</h4>" << std::endl;
					tabs(3); std::cout << "<ol>" << std::endl;
					for (int i = 0; i < cit->descriptions.size(); ++i) {
						tabs(4); std::cout << "<li>"; nl2br(cit->descriptions[i], 4); std::cout << "</li>" << std::endl;
					}
					tabs(3); std::cout << "</ol>" << std::endl;
				}
				if (!cit->notes.empty()) {
					tabs(3); std::cout << "<h4>Notes:</h4>" << std::endl;
					tabs(3); std::cout << "<p>";
					nl2br(cit->notes, 3);
					std::cout << "</p>" << std::endl;
				}
				if (!cit->also.empty()) {
					tabs(3); std::cout << "<h4>See also:</h4>" << std::endl;
					tabs(3); std::cout << "<p>";
					std::vector<std::string>::iterator ait = cit->also.begin();
					while (ait != cit->also.end()) {
						if (ait != cit->also.begin())
							std::cout << ", ";
						std::cout << "<a href=\"#" << *ait << "\">" << *ait << "</a>";
						++ait;
					}
					std::cout << "</p>" << std::endl;
				}
				tabs(2); std::cout << "</p>" << std::endl;
			}
			++cit;
		}

		// Output help for non-command topics
		std::vector<topic>::iterator tit = topics.begin();
		while (tit != topics.end()) {
			if (!tit->name.empty() && !tit->description.empty()) {
				tabs(2); std::cout << "<hr />" << std::endl;
				tabs(2); std::cout << "<p id=\"" << tit->name << "\">" << std::endl;
				tabs(3); std::cout << "<a href=\"#topiclist\">Up</a>";
				tabs(3); std::cout << "<h3>" << tit->name << "</h3>" << std::endl;
				tabs(3); std::cout << "<p>"; nl2br(tit->description, 3); std::cout << "</p>" << std::endl;
				if (!tit->notes.empty()) {
					tabs(3); std::cout << "<h4>Notes:</h4>" << std::endl;
					tabs(3); std::cout << "<p>";
					nl2br(tit->notes, 3);
					std::cout << "</p>" << std::endl;
				}
				if (!tit->also.empty()) {
					tabs(3); std::cout << "<h4>See also:</h4>" << std::endl;
					tabs(3); std::cout << "<p>";
					std::vector<std::string>::iterator ait = tit->also.begin();
					while (ait != tit->also.end()) {
						if (ait != tit->also.begin())
							std::cout << ", ";
						std::cout << "<a href=\"#" << *ait << "\">" << *ait << "</a>";
						++ait;
					}
					std::cout << "</p>" << std::endl;
				}
				tabs(2); std::cout << "</p>" << std::endl;
			}
			++tit;
		}

		//Close the html file
		tabs(1); std::cout << "<!---footer--->" << std::endl;
		tabs(1); std::cout << "</body>" << std::endl;
		std::cout << "</html>" << std::endl;
	}

    return 0;
}
